package pl.edu.pw.mini.adapter;

import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.NodeList;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Iterator;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.MultipartPostMethod;
import org.apache.commons.httpclient.HttpClient;
//import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import pl.edu.pw.mini.DirtyLogHelper;
import pl.edu.pw.mini.adapter.documents.Document;
import pl.edu.pw.mini.adapter.documents.ZohoDocument;
import pl.edu.pw.mini.adapter.documents.ZohoWorkbook;
import pl.edu.pw.mini.adapter.documents.ZohoTextDocument;
import pl.edu.pw.mini.adapter.documents.ZohoPresentation;
import pl.edu.pw.mini.exceptions.AuthenticationException;
import pl.edu.pw.mini.exceptions.ConnectionException;
import pl.edu.pw.mini.exceptions.InternalException;
import pl.edu.pw.mini.exceptions.InternalRuntimeException;

public class ZohoAdapter implements IAdapter{
    
    private static final int BUFFER_SIZE=4*2048;
    
    private static final String APP_KEY="a989142ee18284dd22ecee52559e3bcc";
    
    public static class ZohoConnectionState implements IConnectionState{
        private String password;
        private String username;
        private String ticket;
        
        public ZohoConnectionState(String username, String pass){
            this.username=username;
            this.password=pass;
        }
        public String getLogin(){
            return username;
        }

        public boolean isPasswordEmpty() {
            return password==null||"".equals(password.trim());
        }
        
        
    }
    
    private class ZohoPhysicalCommunicator{
        private String logIn(String login, String password, String key) throws AuthenticationException,ConnectionException{
            String ticket=null;
            try {
                String loginUrl ="https://accounts.zoho.com/login?servicename=ZohoSheet&FROM_AGENT=true&LOGIN_ID="+login+"&PASSWORD="+password;
                
                HttpClient client = new HttpClient();
                GetMethod getMethod=new GetMethod(loginUrl);
                
                int statusCode1 = client.executeMethod(getMethod);
                String content=new String(getMethod.getResponseBody());
                getMethod.releaseConnection();
                highComm.checkResponse(statusCode1,null);
                
                Map<String,String> kVMap=parseKeyValResponse(content);
                
                String resp=kVMap.get("RESULT");
                if (resp==null || "FALSE".equals(resp)){
                    throw new AuthenticationException();
                } else{
                    ticket = kVMap.get("TICKET");
                }
            } catch(IOException e) {
                throw new ConnectionException(e);
            }
            return ticket;
        }
        
        private StringBuilder getContent(InputStream in) throws IOException{
            StringBuilder sb=new StringBuilder(BUFFER_SIZE);
            byte[] response = new byte[BUFFER_SIZE];
            int i = 0;
            while (i!=-1){
                i = in.read(response);
                if (i==BUFFER_SIZE){
                    sb.append(new String(response));
                } else if (i>0){
                    byte[] responsePart=new byte[i];
                    System.arraycopy(response,0,responsePart,0,i);
                    sb.append(new String(responsePart));
                }
            }
            return sb;
        }
        
        private Map<String, String> parseKeyValResponse(String content){
            HashMap<String, String> map=new HashMap<String, String>();
            String temp[] = content.split("\n");
            for(String s:temp){
                s=s.trim();
                if (s.length()==0){
                    continue;
                }
                if (s.startsWith("#")){
                    continue;
                }
                String keyVal[]=s.split("=");
                if (keyVal.length==2){
                    map.put(keyVal[0].trim(),keyVal[1].trim());
                } else{
                    DirtyLogHelper.append("Unrecognized key-val response: "+s);
                }
            }
            return map;
        }
        
        private ZohoDocument doPostAndGetDocument(MultipartPostMethod parameters,String docParentNodeTag,Document.Type responseType) throws ConnectionException{
            try{
                HttpClient client = new HttpClient();
                client.setConnectionTimeout(8000);
                
                int statusCode1 = client.executeMethod(parameters);
                String content = new String(parameters.getResponseBody());
                org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(content)));
                parameters.releaseConnection();
                highComm.checkResponse(statusCode1,doc);
                
                List<Document> txtdList=extractDocumentsFromDoc(doc,docParentNodeTag,responseType);
                if (txtdList.size()==1){
                    return (ZohoDocument)txtdList.get(0);
                } else{
                    return null;
                }
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        private org.w3c.dom.Document getXMLContent(String url) throws ConnectionException{
            try{
                HttpClient client = new HttpClient();
                GetMethod getMethod=new GetMethod(url);
                
                int statusCode1 = client.executeMethod(getMethod);
                
                String content=new String(getMethod.getResponseBody());
                //System.out.println(content);
                getMethod.releaseConnection();
                org.w3c.dom.Document doc =DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(content)));
                highComm.checkResponse(statusCode1,doc);
                return doc;
                
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        private byte[] downloadByteContent(String downloadUrl) throws ConnectionException{
            try{
                HttpClient client = new HttpClient();
                GetMethod getMethod=new GetMethod(downloadUrl);
                
                int statusCode1 = client.executeMethod(getMethod);
                
                byte[] content=getMethod.getResponseBody();
                
                getMethod.releaseConnection();
                highComm.checkResponse(statusCode1,null);
                return content;
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        
    }
    
    private interface DocumentHandler{
        public Document.Type getType();
        public ZohoDocument update(String ticket, String key,File file,String documentId,String updateLock) throws ConnectionException;
        public ZohoDocument update(ZohoConnectionState zcs,String filePath,String documentId,String updateLock) throws ConnectionException;
        public ZohoDocument update(ZohoConnectionState zcs,File file,String documentId,String updateLock) throws ConnectionException;
        public ZohoDocument upload(String ticket, String key,File file,String documentName) throws ConnectionException;
        public ZohoDocument upload(ZohoConnectionState zcs,File file,String documentName)throws ConnectionException;
        public ZohoDocument upload(ZohoConnectionState zcs,String filePath,String documentName)throws ConnectionException;
        public List<Document> getList(ZohoConnectionState zcs) throws ConnectionException;
        public List<Document> getList(String ticket, String key) throws ConnectionException;
        public String getUploadResultNodeTag();
        public String getUpdateResultNodeTag();
        public String getListResultNodeTag();
        public String getContentNodeTag();
        public ZohoDocument getNewDocumentInstance(Node n);
        public org.w3c.dom.Document getRawList(String ticket,String key) throws ConnectionException;
        public org.w3c.dom.Document getContent(String ticket,String key, String documentId) throws ConnectionException;
        public byte[] download(ZohoConnectionState zcs, String documentId) throws ConnectionException;
        public byte[] download(String ticket,String key, String documentId) throws ConnectionException;
        public boolean matchExpresionInContent(String expresion,org.w3c.dom.Document content);
        public List<Document> getListByExpression(String ticket,String key,Document.SearchIn searchIn,String expression) throws ConnectionException;
        public List<Document> getListByExpression(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException;
        public String getDocumentURL(ZohoDocument doc);
    }
    
    private abstract class BaseDocumentHandler implements DocumentHandler{
        public String getUploadResultNodeTag() {
            return "result";
        }
        
        public String getUpdateResultNodeTag() {
            return "result";
        }
        
        protected ZohoDocument executeDoPostAndGetDocument(MultipartPostMethod mPost,String tag) throws ConnectionException{
            return (ZohoDocument)communicator.doPostAndGetDocument(mPost,tag,getType());
        }
        
        public List<Document> getList(ZohoConnectionState zcs) throws ConnectionException{
            logInAuthenticated(zcs);
            return getList(zcs.ticket,APP_KEY);
        }
        
        public List<Document> getList(String ticket, String key) throws ConnectionException {
            try {
                return extractDocumentsFromDoc(getRawList(ticket,key),getListResultNodeTag(),getType());
            } catch(Exception e) {
                throw new ConnectionException(e);
            }
            
        }
        public ZohoDocument upload(ZohoConnectionState zcs,File file,String documentName)throws ConnectionException{
            logInAuthenticated(zcs);
            return upload(zcs.ticket, APP_KEY,file,documentName);
        }
        
        
        public ZohoDocument upload(ZohoConnectionState zcs,String filePath,String documentName)throws ConnectionException{
            logInAuthenticated(zcs);
            return upload(zcs.ticket, APP_KEY,new File(filePath),documentName);
        }
        
        
        public ZohoDocument update(ZohoConnectionState zcs,String filePath,String documentId,String updateLock) throws ConnectionException{
            logInAuthenticated(zcs);
            return update(zcs.ticket, APP_KEY,new File(filePath),documentId,updateLock);
        }
        public ZohoDocument update(ZohoConnectionState zcs,File file,String documentId,String updateLock) throws ConnectionException{
            logInAuthenticated(zcs);
            return update(zcs.ticket, APP_KEY,file,documentId,updateLock);
        }
        public byte[] download(ZohoConnectionState zcs, String documentId) throws ConnectionException{
            logInAuthenticated(zcs);
            return download(zcs.ticket,APP_KEY,documentId);
        }
        public List<Document> getListByExpression(String ticket,String key,Document.SearchIn searchIn,String expression) throws ConnectionException{
            ArrayList<Document> lMatching=new ArrayList<Document>();
            List<Document> lWbook=this.getList(ticket,key);
            for(Document wb:lWbook){
                ZohoDocument zh=(ZohoDocument)wb;
                if(searchIn.equals(Document.SearchIn.NAME)){
                    if(zh.getTitle().indexOf(expression)!=-1){
                        lMatching.add(wb);
                    }
                } else if(searchIn.equals(Document.SearchIn.CONTENT)){
                    org.w3c.dom.Document content = getContent(ticket,key,zh.getId());
                    if(matchExpresionInContent(expression,content))
                        lMatching.add(wb);
                }
            }
            return lMatching;
        }
        public List<Document> getListByExpression(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException{
            logInAuthenticated(zcs);
            return getListByExpression(zcs.ticket,APP_KEY,searchIn,expression);
        }
        public boolean matchExpresionInContent(String expresion,org.w3c.dom.Document content){
            //TODO !!!
            NodeList htmlContent = content.getElementsByTagName(getContentNodeTag());
            for(int i=0;i<htmlContent.getLength();i++){
                String body = htmlContent.item(i).getTextContent();
                if(body.indexOf(expresion)!=-1)
                    return true;
            }
            return false;
        }
    }
    
    /////////---------------- SHEEEEEEEEEET
    
    
    private class WorkbookDocumentHandler extends BaseDocumentHandler{
        public Document.Type getType() {
            return Document.Type.SPREADSHEET;
        }
        
        public ZohoWorkbook update(String ticket, String key, File file, String documentId, String updateLock) throws ConnectionException {
            String uploadUrl="http://sheet.zoho.com/api/private/xml/savebook/"+documentId+"?apikey="+key+"&ticket="+ticket;
            MultipartPostMethod mPost = new MultipartPostMethod(uploadUrl);
            try{
                mPost.addParameter("content", file);
                mPost.addParameter("updateLock",updateLock);
                return (ZohoWorkbook)executeDoPostAndGetDocument(mPost,getUpdateResultNodeTag());
            } catch(ConnectionException e){
                throw e;
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        
        public ZohoWorkbook upload(String ticket, String key, File file, String documentName) throws ConnectionException {
            String uploadUrl="http://sheet.zoho.com/api/private/xml/uploadbook?apikey="+key+"&ticket="+ticket;
            try{
                MultipartPostMethod mPost = new MultipartPostMethod(uploadUrl);
                mPost.addParameter("content", file);
                mPost.addParameter("workbookName", documentName);
                return (ZohoWorkbook)executeDoPostAndGetDocument(mPost,getUploadResultNodeTag());
            } catch(ConnectionException e){
                throw e;
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        
        public byte[] download(String ticket,String key, String documentId) throws ConnectionException{
            String downloadUrl = "http://sheet.zoho.com/api/private/xls/download/"+documentId+"?apikey="+key+"&ticket="+ticket;
            return communicator.downloadByteContent(downloadUrl);
        }
        
        public String getListResultNodeTag() {
            return "workbook";
        }
        
        public ZohoDocument getNewDocumentInstance(Node n) {
            return new ZohoWorkbook(n);
        }
        
        public org.w3c.dom.Document getRawList(String ticket,String key) throws ConnectionException{
            String url="http://sheet.zoho.com/api/private/xml/books?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        public org.w3c.dom.Document getContent(String ticket,String key, String documentId) throws ConnectionException{
            String url="http://sheet.zoho.com/api/private/xml/content/"+documentId+"?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        
        public String getContentNodeTag() {
            return "cell";
        }

        public String getDocumentURL(ZohoDocument doc) {
            return "http://sheet.zoho.com/open.do?docid="+doc.getId();
        }
    }
    
    
    
    /////////---------------- TEXT
    
    
    
    private class TextDocumentHandler extends BaseDocumentHandler{
        public Document.Type getType() {
            return Document.Type.TEXT;
        }
        
        public ZohoTextDocument update(String ticket, String key, File file, String documentId, String updateLock) throws ConnectionException,InternalRuntimeException {
            throw new InternalRuntimeException("Zoho service does not support update of "+getType().toString()+" documents.");
//            String uploadUrl="http://export.writer.zoho.com/api/private/xml/saveDocument/"+documentId+"?apikey="+key+"&ticket="+ticket;
//            MultipartPostMethod mPost = new MultipartPostMethod(uploadUrl);
//            try{
//                mPost.addParameter("content", file);
//                //TODO
//                return (ZohoTextDocument)executeDoPostAndGetDocument(mPost,getUpdateResultNodeTag());
//            } catch(ConnectionException e){
//                throw e;
//            } catch(Exception e){
//                throw new ConnectionException(e);
//            }
        }
        
        public ZohoTextDocument upload(String ticket, String key, File file, String documentName) throws ConnectionException {
            String uploadUrl="http://export.writer.zoho.com/api/private/xml/uploadDocument?apikey="+key+"&ticket="+ticket;
            try{
                MultipartPostMethod mPost = new MultipartPostMethod(uploadUrl);
                mPost.addParameter("content", file);
                //TODO set document name
                return (ZohoTextDocument)executeDoPostAndGetDocument(mPost,getUploadResultNodeTag());
            } catch(ConnectionException e){
                throw e;
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        
        public String getListResultNodeTag() {
            return "document";
        }
        
        public ZohoDocument getNewDocumentInstance(Node n) {
            return new ZohoTextDocument(n);
        }
        
        public org.w3c.dom.Document getRawList(String ticket, String key) throws ConnectionException {
            String url="http://export.writer.zoho.com/api/private/xml/documents?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        
        public org.w3c.dom.Document getContent(String ticket, String key, String documentId) throws ConnectionException {
            String url="http://export.writer.zoho.com/api/private/xml/content/"+documentId+"?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        
        public byte[] download(String ticket, String key, String documentId) throws ConnectionException {
            String downloadUrl = "http://export.writer.zoho.com/api/private/odt/download/"+documentId+"?apikey="+key+"&ticket="+ticket;
            return communicator.downloadByteContent(downloadUrl);
        }
        
        public String getContentNodeTag() {
            return "content";
        }
        public String getDocumentURL(ZohoDocument doc) {
            throw new InternalRuntimeException("Zoho service does not support direct opening of "+getType().toString()+" documents.");
            //return "http://writer.zoho.com/editor.do?docId="+(((ZohoTextDocument)doc).getUrlId());
        }        
        
    }
    
    /////////---------------- PRESENTATION
    
    
    private class PresentationDocumentHandler extends BaseDocumentHandler{
        public Document.Type getType() {
            return Document.Type.PRESENTATION;
        }
        
        public ZohoDocument update(String ticket, String key, File file, String documentId, String updateLock) {
            throw new InternalRuntimeException("Zoho service does not support upload of "+getType().toString()+" documents.");
        }
        
        public ZohoPresentation upload(String ticket, String key, File file, String documentName) throws ConnectionException {
            String uploadUrl="http://show.zoho.com/api/private/xml/uploadpresentation?apikey="+key+"&ticket="+ticket;
            try{
                MultipartPostMethod mPost = new MultipartPostMethod(uploadUrl);
                mPost.addParameter("content", file);
                mPost.addParameter("presentationname",documentName);
                return (ZohoPresentation)executeDoPostAndGetDocument(mPost,getUploadResultNodeTag());
            } catch(ConnectionException e){
                throw e;
            } catch(Exception e){
                throw new ConnectionException(e);
            }
        }
        
        public String getListResultNodeTag() {
            return "presentation";
        }
        
        public ZohoDocument getNewDocumentInstance(Node n) {
            return new ZohoPresentation(n);
        }
        
        public org.w3c.dom.Document getRawList(String ticket, String key) throws ConnectionException {
            String url="http://show.zoho.com/api/private/xml/presentations?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        
        public org.w3c.dom.Document getContent(String ticket, String key, String documentId) throws ConnectionException {
            String url="http://show.zoho.com/api/private/xml/content/"+documentId+"?apikey="+key+"&ticket="+ticket;
            return communicator.getXMLContent(url);
        }
        
        public byte[] download(String ticket, String key, String documentId) throws ConnectionException {
            throw new InternalRuntimeException("Zoho service does not support download of "+getType().toString()+" documents.");
        }
        
        public String getContentNodeTag() {
            return "slideContent";
        }

        public String getDocumentURL(ZohoDocument doc) {
            return "http://show.zoho.com/editor.do?P_ID="+doc.getId();
        }

    }
    
    private class ZohoLogicalCommunicator{
        private void checkResponse(int statusCode,org.w3c.dom.Document response) throws ConnectionException{
            if(statusCode != 200){
                String submess="";
                XStream xstr= new XStream();
                if (response!=null){
                    submess=xstr.toXML(response);
                }
                DirtyLogHelper.append(statusCode+"/////"+submess);
                throw new ConnectionException(statusCode+"");
            }
            if(response==null){
                return;
            }
            NodeList list = response.getElementsByTagName("error");
            if(list.getLength() == 0)
                return;
            Node n = list.item(0);
            list = n.getChildNodes();
            Map<String,String> hmap=new HashMap<String,String>();
            for(int i=0;i<list.getLength();i++){
                n=list.item(i);
                hmap.put(n.getNodeName(),n.getTextContent());
            }
            String message="";
            Iterator i = hmap.entrySet().iterator();
            while(i.hasNext()){
                Map.Entry entry = (Map.Entry)i.next();
                message+=(String)entry.getKey()+": "+(String)entry.getValue()+"\n";
            }
            throw new ConnectionException(message);
        }
        
    }
    
    private ZohoPhysicalCommunicator communicator=new ZohoPhysicalCommunicator();
    
    private ZohoLogicalCommunicator highComm=new ZohoLogicalCommunicator();
    
    private final Map<Document.Type,DocumentHandler> documentHandlerMap;
    
    {
        Map<Document.Type,DocumentHandler> docHand= new HashMap<Document.Type,DocumentHandler>();
        docHand.put(Document.Type.SPREADSHEET,new WorkbookDocumentHandler());
        docHand.put(Document.Type.TEXT,new TextDocumentHandler());
        docHand.put(Document.Type.PRESENTATION,new PresentationDocumentHandler());
        documentHandlerMap=Collections.unmodifiableMap(docHand);
    }
    
    private static ZohoAdapter zAdapter = new ZohoAdapter();
    
    private ZohoAdapter() {
        
    }
    
    public static ZohoAdapter getAdapter(){
        return zAdapter;
    }
    
    
    
//////////////-----------------------------------------------------------------
    
    
    public void logIn(IConnectionState cs) throws AuthenticationException,ConnectionException {
        ZohoConnectionState zcs=(ZohoConnectionState)cs;
        zcs.ticket=communicator.logIn(zcs.username, zcs.password, APP_KEY);
    }
    public void logInAuthenticated(ZohoConnectionState zcs) throws ConnectionException {
        try{
            zcs.ticket=communicator.logIn(zcs.username, zcs.password, APP_KEY);
        } catch(AuthenticationException ex){
            DirtyLogHelper.append(ex);
        }
    }
    
    
    
    private List<Document> extractDocumentsFromDoc(org.w3c.dom.Document doc,String tag,Document.Type docType) throws InternalException{
        NodeList list = doc.getElementsByTagName(tag);
        int size= list.getLength();
        ArrayList<Document> wbList=new ArrayList<Document>(size);
        for(int i=0;i<size;i++){
            Node n = list.item(i);
            wbList.add(generateDocumentForDocumentType(docType,n));
        }
        return wbList;
    }
    
//getList
    public List<Document> getListOfSheets(ZohoConnectionState zcs) throws ConnectionException{
        return getList(zcs,Document.Type.SPREADSHEET);
    }
    
    public List<Document> getListOfTextDocuments(ZohoConnectionState zcs) throws ConnectionException{
        return getList(zcs,Document.Type.TEXT);
    }
    
    public List<Document> getListOfPresentations(ZohoConnectionState zcs) throws ConnectionException{
        return getList(zcs,Document.Type.PRESENTATION);
    }
    
    public List<Document> getList(ZohoConnectionState zcs,Document.Type docType) throws ConnectionException{
        return documentHandlerMap.get(docType).getList(zcs);
    }
    
//download
    public byte[] downloadSheet(ZohoConnectionState zcs, ZohoWorkbook wb)throws ConnectionException{
        return download(zcs, wb.getId(),Document.Type.SPREADSHEET);
    }
    
    public byte[] downloadTextDocument(ZohoConnectionState zcs, ZohoTextDocument txtd)throws ConnectionException{
        return download(zcs,txtd.getId(),Document.Type.TEXT);
    }
    
    
    public byte[] download(ZohoConnectionState zcs, String documentId,Document.Type docType)throws ConnectionException{
        return documentHandlerMap.get(docType).download(zcs, documentId);
    }
    
//upload
    public ZohoWorkbook uploadSheet(ZohoConnectionState zcs,File file,String workbookName)throws ConnectionException{
        return (ZohoWorkbook) upload(zcs, file,workbookName,Document.Type.SPREADSHEET);
    }
    
    public ZohoWorkbook uploadSheet(ZohoConnectionState zcs,String filePath,String workbookName)throws ConnectionException{
        return (ZohoWorkbook) upload(zcs, new File(filePath),workbookName,Document.Type.SPREADSHEET);
    }
    
    public ZohoTextDocument uploadTextDocument(ZohoConnectionState zcs,File file,String documentName)throws ConnectionException{
        return (ZohoTextDocument) upload(zcs,file,documentName,Document.Type.TEXT);
    }
    public ZohoTextDocument uploadTextDocument(ZohoConnectionState zcs,String filePath,String documentName)throws ConnectionException{
        return (ZohoTextDocument) upload(zcs,new File(filePath),documentName,Document.Type.TEXT);
    }
    
    public ZohoPresentation uploadPresentation(ZohoConnectionState zcs,File file,String presentationName)throws ConnectionException{
        return (ZohoPresentation) upload(zcs,file,presentationName,Document.Type.PRESENTATION);
    }
    public ZohoPresentation uploadPresentation(ZohoConnectionState zcs,String filePath,String presentationName)throws ConnectionException{
        return (ZohoPresentation) upload(zcs,new File(filePath),presentationName,Document.Type.PRESENTATION);
    }
    public ZohoDocument upload(ZohoConnectionState zcs,File file,String documentName,Document.Type docType) throws ConnectionException{
        return documentHandlerMap.get(docType).upload(zcs,file,documentName);
    }
    
    
//update
    public ZohoTextDocument updateTextDocument(ZohoConnectionState zcs,String filePath,String documentId) throws ConnectionException{
        return (ZohoTextDocument) update(zcs,new File(filePath),documentId,null,Document.Type.TEXT);
    }
    public ZohoTextDocument updateTextDocument(ZohoConnectionState zcs,File file,String documentId) throws ConnectionException{
        return (ZohoTextDocument) update(zcs,file,documentId,null,Document.Type.TEXT);
    }
    public ZohoWorkbook updateSheet(ZohoConnectionState zcs,String filePath,String workbookId,String updateLock) throws ConnectionException{
        return updateSheet(zcs,new File(filePath),workbookId,updateLock);
    }
    public ZohoWorkbook updateSheet(ZohoConnectionState zcs,File file,String workbookId,String updateLock) throws ConnectionException{
        return (ZohoWorkbook) update(zcs,file,workbookId,updateLock,Document.Type.SPREADSHEET);
    }
    public ZohoDocument update(ZohoConnectionState zcs,File file,String documentId,String updateLock,Document.Type docType) throws ConnectionException{
        return documentHandlerMap.get(docType).update(zcs,file,documentId,updateLock);
    }
    
    
    
//getListByExpression
    public List<Document> getListOfSheetsByExpresion(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException{
        return getListByExpresion(zcs,searchIn,expression,Document.Type.SPREADSHEET);
    }
    public List<Document> getListOfTextDocumentsByExpresion(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException{
        return getListByExpresion(zcs,searchIn,expression,Document.Type.TEXT);
    }
    public List<Document> getListOfPresentationsByExpresion(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException{
        return getListByExpresion(zcs,searchIn,expression,Document.Type.PRESENTATION);
    }
    public List<Document> getListByExpresion(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression,Document.Type docType) throws ConnectionException{
        return documentHandlerMap.get(docType).getListByExpression(zcs,searchIn,expression);
    }
    
    
    public IConnectionState createConnectionState(String login, String password) {
        return new ZohoConnectionState(login,password);
    }
    
    public List<Document> getListOfDocuments(ZohoConnectionState zcs) throws ConnectionException{
        logInAuthenticated(zcs);
        ArrayList<Document> docList=new ArrayList<Document>();
        Collection<DocumentHandler>coll= documentHandlerMap.values();
        for(DocumentHandler dh:coll){
            docList.addAll(dh.getList(zcs));
        }
        return docList;
    }
    public List<Document> getListOfDocumentsByExpresion(ZohoConnectionState zcs,Document.SearchIn searchIn,String expression) throws ConnectionException{
        logInAuthenticated(zcs);
        ArrayList<Document> docList=new ArrayList<Document>();
        Collection<DocumentHandler>coll= documentHandlerMap.values();
        for(DocumentHandler dh:coll){
            docList.addAll(dh.getListByExpression(zcs,searchIn,expression));
        }
        return docList;
    }
    public byte[] getDocumentContent(ZohoConnectionState zcs, ZohoDocument doc) throws ConnectionException, InternalException{
        return documentHandlerMap.get(doc.getType()).download(zcs,doc.getId());
    }
    

    private ZohoDocument generateDocumentForDocumentType(Document.Type docType, Node n) throws InternalException {
        return documentHandlerMap.get(docType).getNewDocumentInstance(n);
    }
    
    public String getDocumentURL(ZohoDocument doc){
        return documentHandlerMap.get(doc.getType()).getDocumentURL(doc);
    }
}
